package com.wjk.kylin.modules.system.schedule.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wjk.kylin.core.constant.ScheduleConstants;
import com.wjk.kylin.core.exception.RequestException;
import com.wjk.kylin.core.job.ScheduleUtils;
import com.wjk.kylin.core.utils.SpringContextHolder;
import com.wjk.kylin.modules.system.schedule.entity.Schedule;
import com.wjk.kylin.modules.system.schedule.mapper.ScheduleMapper;
import com.wjk.kylin.modules.system.schedule.service.IScheduleService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;


/**
 * <p>
 * 定时任务 服务实现类
 * </p>
 *
 * @author wangjkui
 * @since 2020-06-04
 */
@Slf4j
@Service
@Transactional(readOnly = true)
public class ScheduleServiceImpl extends ServiceImpl<ScheduleMapper, Schedule> implements IScheduleService {
    @Autowired
    private Scheduler scheduler;

    /**
     * 项目启动时，初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理（注：不能手动修改数据库ID和任务组名，否则会导致脏数据）
     */
    @PostConstruct
    public void init(){
        List<Schedule> list = super.list();
        for(Schedule schedule : list){
            // 线上重启项目时，类尚未加载，报错
            // validSchedule(schedule);

            //如果不存在，则创建
            ScheduleUtils.createScheduleJob(scheduler, schedule);
        }
    }

    @Override
    public IPage<Schedule> findPage(Page<Schedule> page, Schedule schedule) {
        return baseMapper.findPage(page, schedule);
    }

    @Override
    @Transactional(readOnly = false)
    public boolean save(Schedule schedule){
        validSchedule(schedule);
        schedule.preInsert();

        schedule.setStatus(ScheduleConstants.Status.PAUSE.getValue());
        boolean flag = super.save(schedule);
        if (flag) {
            ScheduleUtils.createScheduleJob(scheduler, schedule);
        }
        return flag;
    }



    @Override
    @Transactional(readOnly = false)
    public boolean update(Schedule schedule){
        validSchedule(schedule);
        schedule.preUpdate();
        //分组可编辑 获取旧分组名称
        Schedule oldSchedule = super.getById(schedule.getId());

        boolean flag = super.updateById(schedule);

        if (flag) {
            ScheduleUtils.updateSchedulerJob(scheduler, schedule, oldSchedule.getJobGroup());
        }
        return flag;
    }

    @Override
    @Transactional(readOnly = false)
    public boolean deleteByIds(String[] scheduleIds){
        List<String> ids = Arrays.asList(scheduleIds);

        List<Schedule> list = super.listByIds(ids);

        boolean flag = super.removeByIds(ids);

        if(flag){
            list.forEach(schedule->{
                ScheduleUtils.deleteScheduleJob(scheduler,schedule);
            });
        }

//        for (String scheduleId : scheduleIds) {
//            Schedule schedule = super.getById(scheduleId);
//            flag = super.removeById(scheduleId);
//            if (flag){
//                ScheduleUtils.deleteScheduleJob(scheduler,schedule);
//            }else{
//                return false;//失败
//            }
//        }
        return flag;
    }

    @Override
    @Transactional(readOnly = false)
    public void run(String scheduleId){
        Schedule schedule = super.getById(scheduleId);
        ScheduleUtils.run(scheduler,schedule);
    }


    @Override
    @Transactional(readOnly = false)
    public boolean changeStatus(String scheduleId,String status){
        Schedule schedule = super.getById(scheduleId);
        boolean flag = false;
        if (ScheduleConstants.Status.NORMAL.getValue().equals(status)
                && ScheduleConstants.Status.PAUSE.getValue().equals(schedule.getStatus())) {
            flag = resumeJob(schedule);
        } else if (ScheduleConstants.Status.PAUSE.getValue().equals(status)
                && ScheduleConstants.Status.NORMAL.getValue().equals(schedule.getStatus())) {
            flag = pauseJob(schedule);
        }
        return flag;
    }

    /**
     * 暂停任务
     */
    @Transactional(readOnly = false)
    public boolean pauseJob(Schedule schedule){
        schedule.setStatus(ScheduleConstants.Status.PAUSE.getValue());
        boolean flag = super.updateById(schedule);
        if (flag) {
            ScheduleUtils.pauseJob(scheduler,schedule);
        }
        return flag;
    }

    /**
     * 恢复任务
     */
    @Transactional(readOnly = false)
    public boolean resumeJob(Schedule schedule){
        schedule.setStatus(ScheduleConstants.Status.NORMAL.getValue());
        boolean flag = super.updateById(schedule);
        if (flag) {
            ScheduleUtils.resumeJob(scheduler,schedule);
        }
        return flag;
    }

    /*校验*/
    private void validSchedule(Schedule schedule) {
        Object bean = null;
        try {
            bean = SpringContextHolder.getBean(schedule.getBeanName());
        }catch (Exception e){
            throw new RequestException("调用目标不存在！");
        }

        if(bean == null){
            throw new RequestException("调用目标不存在！");
        }
        if(!CronExpression.isValidExpression(schedule.getCronExpression())){
            throw new RequestException("Cron执行表达式错误！");
        }
    }
}
